VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject
END
Attribute VB_Name = "clsMT19937"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Sub MD5Init Lib "advapi32.dll" (ByRef context_ As MD5_CTX)
Private Declare Sub MD5Update Lib "advapi32.dll" ( _
  ByRef context_ As MD5_CTX, _
  ByRef input_ As Any, _
  ByVal inlen_ As Long)
Private Declare Sub MD5Final Lib "advapi32.dll" (ByRef context As MD5_CTX)
Private Declare Function CryptGenRandom Lib "advapi32.dll" (ByVal hProv As Long, ByVal dwLen As Long, ByRef pbBuffer As Any) As Long

Private Type MD5_CTX
  i(2 - 1) As Long
  buf(4 - 1) As Long
  in_(64 - 1) As Byte
  digest(16 - 1) As Byte
End Type

'/* Mersenne Twister random number generator (Matsumora and Nishimura,
' * 1996).  It is a twisted GFSR(624,397) with a period of 2^19937-1.
' */

Private Const MT_LEN As Long = 624
Private Const MT_IA As Long = 397
Private Const MT_IB As Long = MT_LEN - MT_IA
Private Const UPPER_MASK As Long = &H80000000
Private Const LOWER_MASK As Long = &H7FFFFFFF
Private Const MATRIX_A As Long = &H9908B0DF
'#define TWIST(b, i, j)  ((b)[i] & UPPER_MASK) | ((b)[j] & LOWER_MASK)
'#define MAGIC(s)    (((s) & 1) * MATRIX_A)

Private mt_index As Long
'static unsigned long mt_buffer[MT_LEN];
Private mt_buffer(MT_LEN - 1) As Long

'static void mt_random_init(void)
'{
'  int i;
'  for (i= 0;  i < MT_LEN;  ++i)
'    /* substitute pseudo-random seed for non-reproducible sequence */
'    mt_buffer[i]= i * 1073741827;
'  mt_index= 0;
'}

'call Randomize first!
Friend Sub mt_random_init_19937()
On Error Resume Next
Dim i As Long, j As Long
For i = 0 To MT_LEN - 1
 j = CLng(Int(Rnd * 2147483648# + Rnd * 128#)) 'Rnd in VB6 is 24-bit random generator
 If Rnd < 0.5 Then j = j Or &H80000000
 mt_buffer(i) = j
Next i
mt_index = 0
End Sub

Friend Sub mt_random_init_19937_2(ByVal lp As Long, ByVal nSize As Long)
Dim i As Long
Dim t As MD5_CTX
'///
If nSize <= 0 Then
 mt_random_init_19937
Else
 If nSize > MT_LEN * 4& Then nSize = MT_LEN * 4&
 CopyMemory mt_buffer(0), ByVal lp, nSize
 '///
 If nSize And &HF& Then
  MD5Init t
  MD5Update t, mt_buffer(0), nSize
  MD5Final t
  nSize = nSize And &HFFFFFFF0
  CopyMemory mt_buffer(nSize \ 4&), t.digest(0), 16&
  nSize = nSize + 16&
 End If
 '///
 For i = nSize \ 4& To MT_LEN - 4 Step 4
  MD5Init t
  MD5Update t, mt_buffer(0), i * 4&
  MD5Final t
  CopyMemory mt_buffer(i), t.digest(0), 16&
 Next i
 '///
 mt_index = 0
End If
End Sub

Friend Sub mt_random_init_crypto_time(ByVal hProv As Long, ByVal tt As Currency)
Dim t As MD5_CTX
CryptGenRandom hProv, MT_LEN * 4& - 16&, mt_buffer(0)
CopyMemory mt_buffer(MT_LEN - 4), tt, 8&
MD5Init t
MD5Update t, mt_buffer(0), MT_LEN * 4& - 8&
MD5Final t
CopyMemory mt_buffer(MT_LEN - 4), t.digest(0), 16&
mt_index = 0
End Sub

Friend Sub mt_random_copy(ByVal src As clsMT19937)
src.mt_random_copy_internal VarPtr(mt_buffer(0)), mt_index
End Sub

Friend Sub mt_random_copy_internal(ByVal dst_buffer As Long, ByRef dst_index As Long)
CopyMemory ByVal dst_buffer, mt_buffer(0), MT_LEN * 4&
dst_index = mt_index
End Sub

'static unsigned long mt_random(void)
'{
'  unsigned long *b= mt_buffer;
'  int idx= mt_index;
'  unsigned long s;
'  int i;
'
'  if (idx == MT_LEN * sizeof(unsigned long))
'    {
'      idx= 0;
'      i= 0;
'      for (;  i < MT_IB;  ++i)
'    {
'      s= TWIST(b, i, i + 1);
'      b[i]= b[i + MT_IA] ^ (s >> 1) ^ MAGIC(s);
'    }
'      for (; i < MT_LEN-1;  ++i)
'    {
'      s= TWIST(b, i, i + 1);
'      b[i]= b[i - MT_IB] ^ (s >> 1) ^ MAGIC(s);
'    }
'      s= TWIST(b, MT_LEN - 1, 0);
'      b[MT_LEN - 1]= b[MT_IA - 1] ^ (s >> 1) ^ MAGIC(s);
'    }
'  mt_index= idx + sizeof(unsigned long);
'  return *(unsigned long *)((unsigned char *)b + idx);
'}

Friend Function mt_random_19937() As Long
Dim idx As Long
Dim s As Long, s1 As Long
Dim i As Long
idx = mt_index
If idx >= MT_LEN Then
 idx = 0
 For i = 0 To MT_IB - 1
  s = (mt_buffer(i) And UPPER_MASK) Or (mt_buffer(i + 1) And LOWER_MASK)
  s1 = ((s And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
  s = ((s And 1&) = 1&) And MATRIX_A
  mt_buffer(i) = mt_buffer(i + MT_IA) Xor s1 Xor s
 Next i
 For i = MT_IB To MT_LEN - 2
  s = (mt_buffer(i) And UPPER_MASK) Or (mt_buffer(i + 1) And LOWER_MASK)
  s1 = ((s And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
  s = ((s And 1&) = 1&) And MATRIX_A
  mt_buffer(i) = mt_buffer(i - MT_IB) Xor s1 Xor s
 Next i
 s = (mt_buffer(MT_LEN - 1) And UPPER_MASK) Or (mt_buffer(0) And LOWER_MASK)
 s1 = ((s And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
 s = ((s And 1&) = 1&) And MATRIX_A
 mt_buffer(MT_LEN - 1) = mt_buffer(MT_IA - 1) Xor s1 Xor s
End If
mt_index = idx + 1
mt_random_19937 = mt_buffer(idx)
End Function

Friend Function mt_random_real() As Double
mt_random_real = CDbl(mt_random_19937) / 4294967296# + 0.5
End Function
